package com.jyh.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jyh.blog.constant.CommonConst;
import com.jyh.blog.dao.ResourceDao;
import com.jyh.blog.dao.RoleResourceDao;
import com.jyh.blog.dto.LabelOptionDTO;
import com.jyh.blog.dto.ResourceDTO;
import com.jyh.blog.entity.Resource;
import com.jyh.blog.entity.RoleResource;
import com.jyh.blog.exception.MyException;
import com.jyh.blog.handler.FilterInvocationSecurityMetadataSourceImpl;
import com.jyh.blog.service.ResourceService;
import com.jyh.blog.utils.BeanCopyUtils;
import com.jyh.blog.vo.AnonymousResourceVO;
import com.jyh.blog.vo.ConditionVO;
import com.jyh.blog.vo.ResourceVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.jyh.blog.constant.CommonConst.FALSE;

/**
 * (Resource)表服务实现类
 *
 * @author jyh
 * @since 2023-02-15 15:43:19
 */
@Service("resourceService")
public class ResourceServiceImpl extends ServiceImpl<ResourceDao, Resource> implements ResourceService {
    @Autowired
    private RoleResourceDao roleResourceDao;
    @Autowired
    private FilterInvocationSecurityMetadataSourceImpl filterInvocationSecurityMetadataSource;
    @Autowired
    private RestTemplate restTemplate;

    @Override
    public List<ResourceDTO> resourceList(ConditionVO conditionVO) {
        String keywords = conditionVO.getKeywords();
        //查询所有
        List<Resource> resourceList = this.list(new LambdaQueryWrapper<Resource>()
                .like(StringUtils.isNotBlank(keywords), Resource::getName, keywords));
        //父模块
        List<Resource> parentMoulds = parentMoulds(resourceList);
        //子模块
        Map<String, List<Resource>> childMap = childMap(resourceList);
        //封装
        List<ResourceDTO> resourceDTOList = BeanCopyUtils.copyList(parentMoulds, ResourceDTO.class).stream().map(item -> {
            List<ResourceDTO> childList = BeanCopyUtils.copyList(childMap.get(item.getId()), ResourceDTO.class);
            item.setChildrenList(childList);
            childMap.remove(item.getId());
            return item;
        }).collect(Collectors.toList());
        //拼接剩余
        if (CollectionUtils.isNotEmpty(childMap)) {
            ArrayList<Resource> list = new ArrayList<>();
            childMap.values().forEach(list::addAll);
            resourceDTOList.addAll(BeanCopyUtils.copyList(list, ResourceDTO.class));
        }
        return resourceDTOList;
    }

    @Override
    public void saveOrUpdateResource(ResourceVO resourceVO) {
        Resource resource = BeanCopyUtils.copyObject(resourceVO, Resource.class);
        this.saveOrUpdate(resource);
        //刷新资源
        filterInvocationSecurityMetadataSource.clearDataSource();


    }

    @Override
    public void deleteResourceById(String id) {
        if (ObjectUtils.isNull(id)) {
            throw new MyException("被删除的资源id不能为空");
        }
        //有角色使用资源时不能删除
        Integer count = roleResourceDao.selectCount(new LambdaQueryWrapper<RoleResource>()
                .eq(RoleResource::getResourceId, id));
        if (count > 0) {
            throw new MyException("有角色正在使用资源,不能删除");
        }
        //id可能为父模块，删除其子模块
        List<String> list = this.list(new LambdaQueryWrapper<Resource>()
                .eq(Resource::getParentId, id))
                .stream().map(Resource::getId)
                .collect(Collectors.toList());
        list.add(id);
        this.removeByIds(list);
    }

    @Override
    public void changAnonymous(AnonymousResourceVO anonymousResourceVO) {
        Resource resource = BeanCopyUtils.copyObject(anonymousResourceVO, Resource.class);
        this.updateById(resource);
    }

    @Override
    public List<LabelOptionDTO> roleResourceList() {
        //查询资源列表
        List<Resource> resourcesList = this.list(new LambdaQueryWrapper<Resource>()
                .select(Resource::getId, Resource::getName, Resource::getParentId)
                .eq(Resource::getIsAnonymous, FALSE)
        );
        //查询资源父菜单
        List<Resource> catalogList = parentMoulds(resourcesList);
        //查询资源子菜单
        Map<String, List<Resource>> childMap = childMap(resourcesList);
        //封装(与menu中同理)
        return catalogList.stream().map(item -> {
            List<LabelOptionDTO> list = new ArrayList<>();
            List<Resource> child = childMap.get(item.getId());
            if (CollectionUtils.isNotEmpty(child)) {
                list = child.stream().map(resource -> LabelOptionDTO.builder()
                        .id(resource.getId())
                        .label(resource.getName())
                        .build()
                ).collect(Collectors.toList());
            }
            return LabelOptionDTO.builder()
                    .id(item.getId())
                    .label(item.getName())
                    .children(list)
                    .build();
        }).collect(Collectors.toList());
    }

    /**
     * 获取父模块
     *
     * @param resources
     * @return
     */
    private List<Resource> parentMoulds(List<Resource> resources) {
        return resources.stream()
                .filter(item -> ObjectUtils.isNull(item.getParentId()))
                .collect(Collectors.toList());
    }

    /**
     * 获取子模块
     *
     * @param resources
     * @return
     */
    private Map<String, List<Resource>> childMap(List<Resource> resources) {
        return resources.stream()
                .filter(item -> ObjectUtils.isNotNull(item.getParentId()))
                .collect(Collectors.groupingBy(Resource::getParentId));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void importSwagger() {
        // 删除所有资源
        this.remove(null);
        roleResourceDao.delete(null);
        List<Resource> resourceList = new ArrayList<>();
        Map<String, Object> data = restTemplate.getForObject("http://localhost:7777/v2/api-docs?group=webApi", Map.class);
        // 获取所有模块
        List<Map<String, String>> tagList = (List<Map<String, String>>) data.get("tags");
        tagList.forEach(item -> {
            Resource resource = Resource.builder()
                    .name(item.get("name"))
                    .isAnonymous(CommonConst.FALSE)
                    .build();
            resourceList.add(resource);
        });
        this.saveBatch(resourceList);
        Map<String, String> permissionMap = resourceList.stream()
                .collect(Collectors.toMap(Resource::getName, Resource::getId));
        resourceList.clear();
        // 获取所有接口
        Map<String, Map<String, Map<String, Object>>> path = (Map<String, Map<String, Map<String, Object>>>) data.get("paths");
        path.forEach((url, value) -> value.forEach((requestMethod, info) -> {
            String permissionName = info.get("summary").toString();
            List<String> tag = (List<String>) info.get("tags");
            String parentId = permissionMap.get(tag.get(0));
            Resource resource = Resource.builder()
                    .name(permissionName)
                    .url(url.replaceAll("\\{[^}]*\\}", "*"))
                    .parentId(parentId)
                    .requestMethod(requestMethod.toUpperCase())
                    .isAnonymous(CommonConst.FALSE)
                    .build();
            resourceList.add(resource);
        }));
        this.saveBatch(resourceList);
    }
}

